package org.liang.email4j.submail;

import java.util.Map.Entry;

import jodd.http.HttpRequest;
import jodd.http.HttpResponse;

import org.liang.email4j.Email;
import org.liang.email4j.EmailSender;
import org.liang.email4j.Response;
import org.liang.email4j.helper.AddressCodec;
import org.liang.email4j.submail.util.RequestEncoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

/**
 * 使用第三方服务商 进行邮件发送.
 * 
 * <pre>
 * 如果邮件发送失败直接返回失败信息。
 * </pre>
 * 
 * @author L.Yang
 * @version v1.0 2015年12月31日 下午2:31:57
 */
public class SubmailSender implements EmailSender {

    private Logger logger = LoggerFactory.getLogger(SubmailSender.class);

    /** 邮件发送API 请求地址. */
    private static final String URL_API_SEND = "http://api.submail.cn/mail/send.json";

    /** 邮件发送时间戳API 请求地址. */
    private static final String URL_API_TIMESTAMP = "http://api.submail.cn/service/timestamp.json";

    /** 邮件服务 应用编号 键值. */
    private static final String APPID = "appid";

    /** 邮件服务 时间戳 键值 . */
    private static final String TIMESTAMP = "timestamp";

    /** 邮件服务 签名加密类型. */
    private static final String SIGN_TYPE = "sign_type";

    /** 邮件服务 签名 键值. */
    private static final String SIGNATURE = "signature";

    @Override
    public Response send(Email email) {
        RequestData requestData = new RequestData();

        requestData.setFrom(email.getFrom(), email.getFromname());
        requestData.setReply(email.getReplyto());
        for (String address : email.getTo()) {
            requestData.addTo(AddressCodec.getEmail(address), AddressCodec.getName(address));
        }
        for (String address : email.getCc()) {
            requestData.addCc(AddressCodec.getEmail(address), AddressCodec.getName(address));
        }
        for (String address : email.getBcc()) {
            requestData.addBcc(AddressCodec.getEmail(address), AddressCodec.getName(address));
        }
        requestData.setSubject(email.getSubject());
        requestData.setText(SubmailConfig.getEmailText());
        requestData.setHtml(email.getMsg());

        for (Entry<String, String> entry : email.getHeaders().entrySet()) {
            requestData.addHeaders(entry.getKey(), entry.getValue());
        }

        wrappRequest(requestData);

        for (String attachment : email.getAttachments()) {
            requestData.addAttachment(attachment);
        }

        HttpResponse response = HttpRequest.post(URL_API_SEND).form(requestData).send();
        return buildResult(response);
    }

    /**
     * 将 通用请求参数 加入到请求参数中.
     * 
     * @param requestData
     *            请求参数对象
     */
    private void wrappRequest(RequestData requestData) {
        requestData.put(APPID, SubmailConfig.getAppId());
        requestData.put(TIMESTAMP, this.getTimestamp());
        requestData.put(SIGN_TYPE, SubmailConfig.getSignType());
        requestData.put(SIGNATURE, createSignature(RequestEncoder.formatRequest(requestData)));
    }

    /**
     * 构建远程服务执行结果.
     * 
     * @param response
     *            http响应
     * @return 邮件接口中的请求结果
     */
    private Response buildResult(HttpResponse response) {
        logger.trace("response :{} ", response.body());
        JSONObject obj = JSON.parseObject(response.body());
        Response result = null;
        if (obj.get("status").toString().equalsIgnoreCase(SUCCESS)) {
            result = new Response().success();
        } else {
            result = new Response(Integer.parseInt(
                obj.get("code").toString()), obj.get("msg").toString());
        }
        return result;
    }

    private static final String SUCCESS = "success";

    /**
     * 创建签名.
     * 
     * @param data
     *            参数字符串
     * @return 签名字符串
     */
    private String createSignature(String data) {
        if (SubmailConfig.TYPE_NORMAL.equals(SubmailConfig.getSignType())) {
            return SubmailConfig.getAppKey();
        } else {
            return buildSignature(data);
        }
    }

    /**
     * When the {@link AppConfig#setSignType(String)} is not normal,create a signature with sign
     * type.
     * 
     * @param data
     *            is the request data
     * @return signature
     */
    private String buildSignature(String data) {
        String app = SubmailConfig.getAppId();
        String appKey = SubmailConfig.getAppKey();
        String jointData = app + appKey + data + app + appKey;
        if (SubmailConfig.TYPE_MD5.equals(SubmailConfig.getSignType())) {
            return RequestEncoder.encode(RequestEncoder.MD5, jointData);
        } else if (SubmailConfig.TYPE_SHA1.equals(SubmailConfig.getSignType())) {
            return RequestEncoder.encode(RequestEncoder.SHA1, jointData);
        }
        return jointData;
    }

    /**
     * Send a request to require timestamp from server.
     * 
     * @return timestamp
     */
    private String getTimestamp() {
        HttpResponse response = HttpRequest.get(URL_API_TIMESTAMP).send();
        JSONObject json = JSONObject.parseObject(response.bodyText());
        return json.getString("timestamp");
    }
}
